﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Threading;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using System.ServiceModel;
using WordPressShared;

namespace WorkerRoleSMB
{
    public class WorkerRole : RoleEntryPoint
    {
        private ServiceHost host;
        public static string driveLetter = null;
        public static CloudDrive drive = null;

        public override void Run()
        {
            Trace.TraceInformation("SMBServer entry point called");

            while (true)
            {
                Thread.Sleep(10000);

                try
                {
                    // Compruebo si la instancia actual el servicio SMB activo 
                    SMBService currentSMBService = new SMBService();
                    if (!currentSMBService.IsSMBEnabled())
                    {
                        // La instancia actual NO tiene el servicio SMB activo 

                        // Compruebo la otra instancia tiene activo SMB
                        bool activarSMB = false;
                        if (RoleEnvironment.CurrentRoleInstance.Role.Instances.Count < 2)
                            activarSMB = true; // Solo hay un rol
                        else
                        {
                            // Busca la otra instancia
                            RoleInstance otherInstance = RoleEnvironment.Roles["WorkerRoleSMB"].Instances.First(instance => instance.Id != RoleEnvironment.CurrentRoleInstance.Id);

                            // Consulto si tiene el servicio activo
                            try
                            {
                                for (int i = 0; i < 3; ++i)
                                {
                                    ISMBService remoteService = SMBService.GetAProxy(SMBService.GetUrlFormat(otherInstance.InstanceEndpoints["SMBService"].IPEndpoint));
                                    if (remoteService.IsSMBEnabled())
                                    {
                                        break;
                                    }
                                    if (remoteService.IsLoadingSMB())
                                    {
                                        Thread.Sleep(30000);
                                    }

                                    if (i == 2)
                                        activarSMB = true;
                                }
                            }
                            catch
                            {
                                // Error al llamar al método, puede que esté apagadoo fallo en red
                                activarSMB = true;
                            }
                        }

                        if (activarSMB)
                            MountSMB();
                    }
                    else
                    {
                        // Esta instancia tiene SMB montado
                        // Comprobamos que los WebRoles tienen su servicio apuntando

                        // Notifica a los WebRoles que debe actualizarse
                        foreach (RoleInstance webInstance in RoleEnvironment.Roles["WebCgiRoleWordPress"].Instances)
                        {
                            try
                            {
                                ISMBService remoteService = SMBService.GetAProxy(SMBService.GetUrlFormat(webInstance.InstanceEndpoints["SMBService"].IPEndpoint));
                                if (!remoteService.IsNetWorkDriveSMBConfigured())
                                {
                                    remoteService.ReconnectNetworkDriveSMB(RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["SMBService"].IPEndpoint.Address.ToString());
                                }
                            }
                            catch (Exception ex)
                            {
                            }
                        }
                    }
                }
                catch (Exception ex1)
                {
                }

            }
        }

        public override bool OnStart()
        {
            ServicePointManager.DefaultConnectionLimit = 12;
            try
            {
                StartWCFService();

                // Inits the Diagnostic Monitor
                //RoleStartupUtils.InitializeDiagnosticMonitor();            

                // Al iniciar comprobamos si hay alguna instancia con el servicio SMB levantado
                bool smbLoaded = false;
                foreach (RoleInstance smbInstance in RoleEnvironment.Roles["WorkerRoleSMB"].Instances)
                {
                    if (smbInstance.Id != RoleEnvironment.CurrentRoleInstance.Id)
                    {
                        try
                        {
                            for (int i = 0; i < 3; ++i)
                            {
                                ISMBService remoteService = SMBService.GetAProxy(SMBService.GetUrlFormat(smbInstance.InstanceEndpoints["SMBService"].IPEndpoint));
                                if (remoteService.IsSMBEnabled())
                                {
                                    smbLoaded = true;
                                    break;
                                }
                                if (remoteService.IsLoadingSMB())
                                {
                                    Thread.Sleep(20000);
                                }
                            }

                            if (smbLoaded)
                                break;
                        }
                        catch
                        {
                            // Error al llamar al método, puede que esté apagadoo fallo en red
                        }
                    }
                }

                // Si no hay ninguna instancia con SMB activo compruebo si tengo que iniciarlo la instancia actual
                if (!smbLoaded)
                {
                    if (RoleEnvironment.CurrentRoleInstance.Id == RoleEnvironment.Roles["WorkerRoleSMB"].Instances[0].Id)
                        MountSMB(); // Somos la instancia principal, montamos SMB
                    else
                        Thread.Sleep(10000); // No somos la instancia principal, damos un margen para que monte SMB
                }

            }
            catch (Exception ex)
            {
            }


            return base.OnStart();
        }

        public override void OnStop()
        {
            StopWCFService();

            base.OnStop();
        }

        private void MountSMB()
        {
            SMBService.LoadingSMB = true;

            try
            {

                // Mount the drive
                drive = RoleStartupUtils.MountCloudDrive(RoleEnvironment.GetConfigurationSettingValue("AcceleratorConnectionString"),
                                                        "AzureDriveCache",
                                                        RoleEnvironment.GetConfigurationSettingValue("ImageStoreBlobUri"),
                                                        RoleEnvironment.GetConfigurationSettingValue("driveSize"));
                // Create a local account for sharing the drive
                RoleStartupUtils.CreateUserAccount(RoleEnvironment.GetConfigurationSettingValue("fileshareUserName"),
                                                   RoleEnvironment.GetConfigurationSettingValue("fileshareUserPassword"));
                // Enable SMB traffic through the firewall
                if (RoleStartupUtils.EnableSMBFirewallTraffic() != 0)
                    return;

                //// Share it using SMB (add permissions for RDP user if it's configured)
                string RDPuserName = "";
                try { RDPuserName = RoleEnvironment.GetConfigurationSettingValue("Microsoft.WindowsAzure.Plugins.RemoteAccess.AccountUsername"); }
                catch { };

                RoleStartupUtils.ShareLocalFolder(RoleEnvironment.GetConfigurationSettingValue("fileshareUserName"),
                                                RDPuserName, drive.LocalPath,
                                                RoleEnvironment.GetConfigurationSettingValue("shareName"));


                // Notifica a los WebRoles que debe actualizarse
                foreach (RoleInstance webInstance in RoleEnvironment.Roles["WebCgiRoleWordPress"].Instances)
                {
                    try
                    {
                        ISMBService remoteService = SMBService.GetAProxy(SMBService.GetUrlFormat(webInstance.InstanceEndpoints["SMBService"].IPEndpoint));
                        remoteService.ReconnectNetworkDriveSMB(RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["SMBService"].IPEndpoint.ToString());
                    }
                    catch { }
                }
            }
            catch (Exception ex)
            {
                //Trace.TraceError(ex.ToString());
                //Trace.TraceInformation("Exiting");
                //throw;
            }
            finally
            {
                SMBService.LoadingSMB = false;
            }
        }


        private void StartWCFService()
        {
            try
            {
                IPEndPoint ipEndPoint = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["SMBService"].IPEndpoint;
                host = new ServiceHost(typeof(SMBService));
                NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
                host.AddServiceEndpoint(typeof(ISMBService), binding, SMBService.GetUrlFormat(ipEndPoint));

                host.Open();
            }
            catch (Exception ex)
            {
                Trace.WriteLine(ex.Message, "Error");
                throw;
            }
            Trace.WriteLine("WCF Hello service running...");
        }
        private void StopWCFService()
        {
            try
            {
                if (host != null && host.State == CommunicationState.Opened)
                    host.Close();
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Exception: " + ex.Message, "Information");
            }
        }
    }
}